package com.ctshk.rpc.user.service.impl;

import cn.hutool.core.util.RandomUtil;
import com.ctshk.common.constant.RedisConstants;
import com.ctshk.common.dto.Result;
import com.ctshk.common.enums.SmsType;
import com.ctshk.common.enums.SystemError;
import com.ctshk.common.exception.BusinessException;
import com.ctshk.common.sms.core.SmsUtil;
import com.ctshk.rpc.user.config.SmsConfig;
import com.ctshk.rpc.user.dto.AppUserDTO;
import com.ctshk.rpc.user.service.IUserService;
import com.ctshk.rpc.user.service.IUserValidateService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.dubbo.config.annotation.DubboService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import java.util.concurrent.TimeUnit;

/**
 * <p>
 *  校验服务实现类
 * </p>
 *
 * @author 李新科
 * @date 2021/4/22 15:25
 */
@Slf4j
@DubboService
public class UserValidateServiceImpl implements IUserValidateService {

    @Autowired
    private RedisTemplate<String, Object> redisTemplate;

    @Autowired
    private SmsConfig smsConfig;

    @Autowired
    private IUserService userService;

    @Override
    public Result sendSmsCaptcha(String contactMobileAreaCode,String contactNumber,Integer type,Long userId) throws Exception{
        boolean isNotBlankContactNumber = true;
        if(SmsType.UPDATE_PWD.getType().equals(type) || (SmsType.UPDATE_PHONE.getType().equals(type) && StringUtils.isBlank(contactMobileAreaCode)
            && StringUtils.isBlank(contactNumber))) {
            isNotBlankContactNumber = false;
            AppUserDTO userDTO = userService.queryCacheUser(userId);
            contactMobileAreaCode = userDTO.getContactMobileAreaCode();
            contactNumber = userDTO.getContactNumber();
        }
        String fullContactNumber = contactMobileAreaCode + contactNumber;
        String key = RedisConstants.SMS_CODE_KEY + fullContactNumber + "_" + type;
        Object o = redisTemplate.opsForValue().get(key);

        if(o != null) {
            // 短信间隔两分钟可重发
            Long expire = redisTemplate.getExpire(key, TimeUnit.SECONDS);
            if(expire > 180) {
                throw new BusinessException(SystemError.USER_1019);
            }
        }

        String code = RandomUtil.randomNumbers(4);
        try {
            // 根据验证码类型选择不同的短信模板
            if(SmsType.LOGIN.getType().equals(type)) {
                if(SmsUtil.isDomestic(contactMobileAreaCode)) {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getLoginTemplateCode(),code);
                } else {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getInternationalLoginTemplateCode(),code);
                }

            } else if (SmsType.REGISTER.getType().equals(type)) {
                // 注册需要判断该手机号是否已注册过
                AppUserDTO userDTO = new AppUserDTO();
                userDTO.setContactMobileAreaCode(contactMobileAreaCode);
                userDTO.setContactNumber(contactNumber);
                boolean exists = userService.exists(userDTO);
                if(exists) {
                    return Result.failed(SystemError.USER_1029);
                }
                if(SmsUtil.isDomestic(contactMobileAreaCode)) {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getRegiterTemplateCode(),code);
                } else {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getInternationalRegiterTemplateCode(),code);
                }

            } else if (SmsType.RESET_PWD.getType().equals(type)) {
                if(SmsUtil.isDomestic(contactMobileAreaCode)) {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getResetPwdTemplateCode(),code);
                } else {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getInternationalResetPwdTemplateCode(),code);
                }
            } else if (SmsType.UPDATE_PHONE.getType().equals(type)) {
                if(isNotBlankContactNumber) {
                    // 修改手机时需要判断该手机号是否已注册过
                    AppUserDTO userDTO = new AppUserDTO();
                    userDTO.setContactMobileAreaCode(contactMobileAreaCode);
                    userDTO.setContactNumber(contactNumber);
                    boolean exists = userService.exists(userDTO);
                    if(exists) {
                        return Result.failed(SystemError.USER_1029);
                    }
                }
                if(SmsUtil.isDomestic(contactMobileAreaCode)) {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getUpdatePhoneTemplateCode(),code);
                } else {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getInternationalUpdatePhoneTemplateCode(),code);
                }
            } else if (SmsType.UPDATE_PWD.getType().equals(type)) {
                if(SmsUtil.isDomestic(contactMobileAreaCode)) {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getUpdatePwdTemplateCode(),code);
                } else {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getInternationalUpdatePwdTemplateCode(),code);
                }
            } else if (SmsType.GENERAL.getType().equals(type)) {
                if(SmsUtil.isDomestic(contactMobileAreaCode)) {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getGeneralTemplateCode(),code);
                } else {
                    SmsUtil.sendSmsCode(fullContactNumber,smsConfig.getInternationalGeneralTemplateCode(),code);
                }
            }else {
                throw new BusinessException(SystemError.USER_1021);
            }
        } catch (Exception e) {
            throw new BusinessException(SystemError.SYS_433,e.getMessage());
        }

        //发送短信成功清除错误次数
        String errCountKey = RedisConstants.SMS_ERR_COUNT_CODE_KEY + fullContactNumber + "_" + type;
        redisTemplate.delete(errCountKey);
        redisTemplate.opsForValue().set(key,code,5,TimeUnit.MINUTES);
        return Result.success();
    }

    @Override
    public Result sendSmsCaptcha(String contactMobileAreaCode, String contactNumber, Integer type) throws Exception {
        return sendSmsCaptcha(contactMobileAreaCode,contactNumber,type,null);
    }

    @Override
    public void check(String phone, String code, Integer type, Long userId) throws Exception{
        if(userId != null) {
            AppUserDTO userDTO = userService.queryCacheUser(userId);
            String contactMobileAreaCode = userDTO.getContactMobileAreaCode();
            String contactNumber = userDTO.getContactNumber();
            phone = contactMobileAreaCode + contactNumber;
        }
        if (StringUtils.isBlank(code)) {
            throw new BusinessException(SystemError.USER_1007);
        }

        String key = RedisConstants.SMS_CODE_KEY + phone + "_" + type;
        // 错误次数达到3次清除当前验证码
        String errCountKey = RedisConstants.SMS_ERR_COUNT_CODE_KEY + phone + "_" + type;

        Object o = redisTemplate.opsForValue().get(errCountKey);
        if(o == null) {
            redisTemplate.opsForValue().set(errCountKey,0);
        }

        Object codeFromRedis = redisTemplate.opsForValue().get(key);

        if(codeFromRedis == null) {
            throw new BusinessException(SystemError.USER_1030);
        }

        if (!StringUtils.equals(code, String.valueOf(codeFromRedis))) {
            int count = o == null?0:((Integer) o).intValue();
            if(count >= 2) {
                redisTemplate.delete(errCountKey);
                redisTemplate.delete(key);
            } else {
                redisTemplate.opsForValue().increment(errCountKey);
            }

            throw new BusinessException(SystemError.USER_1018);
        }

        redisTemplate.delete(errCountKey);
        redisTemplate.delete(key);
    }

    @Override
    public void check(String phone, String code, Integer type) throws Exception {
        check(phone, code, type, null);
    }

    @Override
    public Result sendCode(String contactMobileAreaCode, String contactNumber) throws Exception{
        return sendSmsCaptcha(contactMobileAreaCode, contactNumber, 6);
    }

    @Override
    public boolean checkCode(String contactMobileAreaCode, String contactNumber, String code){
        boolean isSuccess = false;
        try {
            check(replacePlus(contactMobileAreaCode) + contactNumber, code, SmsType.GENERAL.getType());
            isSuccess = true;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return isSuccess;
    }

    /**
     * 去除加号
     */
    public String replacePlus(String str) {
        return str.replaceAll("\\+","");
    }
}
